added samples
[windows-sources.git] / sdk / samples / all in on code / Visual Studio 2008 / CppFileHandle / CppFileHandle.cpp
blob31d7fdc8e4ddcb0d9dd29cac3f9dbae90333c6ab
1 /****************************** Module Header ******************************\
2 * Module Name: CppFileHandle.cpp
3 * Project: CppFileHandle
4 * Copyright (c) Microsoft Corporation.
5 *
6 * CppFileHandle demonstrates two typical scenarios of using file handles:
7 *
8 * 1) Enumerate file handles of a process
9 * 2) Get file name from a file handle
11 * This source is subject to the Microsoft Public License.
12 * See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
13 * All other rights reserved.
15 * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
16 * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
18 \***************************************************************************/
20 #pragma region Includes
21 #include <stdio.h>
22 #include <tchar.h>
23 #include <windows.h>
24 #include <psapi.h>
25 #include <strsafe.h>
26 #include <assert.h>
27 #pragma endregion
30 #define BUFFER_SIZE 512
33 #pragma region EnumerateFileHandles
35 #define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
36 #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xc0000004L)
39 #include <winternl.h>
41 // Undocumented SYSTEM_INFORMATION_CLASS: SystemHandleInformation
42 const SYSTEM_INFORMATION_CLASS SystemHandleInformation =
43 (SYSTEM_INFORMATION_CLASS)16;
45 // The NtQuerySystemInformation function and the structures that it returns
46 // are internal to the operating system and subject to change from one
47 // release of Windows to another. To maintain the compatibility of your
48 // application, it is better not to use the function.
49 typedef NTSTATUS (WINAPI * PFN_NTQUERYSYSTEMINFORMATION)(
50 IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
51 OUT PVOID SystemInformation,
52 IN ULONG SystemInformationLength,
53 OUT PULONG ReturnLength OPTIONAL
57 #define HANDLE_TYPE_FILE 28
59 // Undocumented structure: SYSTEM_HANDLE_INFORMATION
60 typedef struct _SYSTEM_HANDLE
62 ULONG ProcessId;
63 UCHAR ObjectTypeNumber;
64 UCHAR Flags;
65 USHORT Handle;
66 PVOID Object;
67 ACCESS_MASK GrantedAccess;
68 } SYSTEM_HANDLE, *PSYSTEM_HANDLE;
70 typedef struct _SYSTEM_HANDLE_INFORMATION
72 ULONG NumberOfHandles;
73 SYSTEM_HANDLE Handles[1];
74 } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
77 // Undocumented FILE_INFORMATION_CLASS: FileNameInformation
78 const FILE_INFORMATION_CLASS FileNameInformation =
79 (FILE_INFORMATION_CLASS)9;
81 // The NtQueryInformationFile function and the structures that it returns
82 // are internal to the operating system and subject to change from one
83 // release of Windows to another. To maintain the compatibility of your
84 // application, it is better not to use the function.
85 typedef NTSTATUS (WINAPI * PFN_NTQUERYINFORMATIONFILE)(
86 IN HANDLE FileHandle,
87 OUT PIO_STATUS_BLOCK IoStatusBlock,
88 OUT PVOID FileInformation,
89 IN ULONG Length,
90 IN FILE_INFORMATION_CLASS FileInformationClass
93 // FILE_NAME_INFORMATION contains name of queried file object.
94 typedef struct _FILE_NAME_INFORMATION {
95 ULONG FileNameLength;
96 WCHAR FileName[1];
97 } FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
101 * Enumerate file handles of the specified process using undocumented APIs.
103 * \param pid
104 * Process Id
106 DWORD EnumerateFileHandles(ULONG pid)
108 /////////////////////////////////////////////////////////////////////////
109 // Prepare for NtQuerySystemInformation and NtQueryInformationFile.
112 // The functions have no associated import library. You must use the
113 // LoadLibrary and GetProcAddress functions to dynamically link to
114 // ntdll.dll.
116 HINSTANCE hNtDll = LoadLibrary(_T("ntdll.dll"));
117 assert(hNtDll != NULL);
119 PFN_NTQUERYSYSTEMINFORMATION NtQuerySystemInformation =
120 (PFN_NTQUERYSYSTEMINFORMATION)GetProcAddress(hNtDll,
121 "NtQuerySystemInformation");
122 assert(NtQuerySystemInformation != NULL);
124 PFN_NTQUERYINFORMATIONFILE NtQueryInformationFile =
125 (PFN_NTQUERYINFORMATIONFILE)GetProcAddress(hNtDll,
126 "NtQueryInformationFile");
129 /////////////////////////////////////////////////////////////////////////
130 // Get system handle information.
133 DWORD nSize = 4096, nReturn;
134 PSYSTEM_HANDLE_INFORMATION pSysHandleInfo = (PSYSTEM_HANDLE_INFORMATION)
135 HeapAlloc(GetProcessHeap(), 0, nSize);
137 // NtQuerySystemInformation does not return the correct required buffer
138 // size if the buffer passed is too small. Instead you must call the
139 // function while increasing the buffer size until the function no longer
140 // returns STATUS_INFO_LENGTH_MISMATCH.
141 while (NtQuerySystemInformation(SystemHandleInformation, pSysHandleInfo,
142 nSize, &nReturn) == STATUS_INFO_LENGTH_MISMATCH)
144 HeapFree(GetProcessHeap(), 0, pSysHandleInfo);
145 nSize += 4096;
146 pSysHandleInfo = (SYSTEM_HANDLE_INFORMATION*)HeapAlloc(
147 GetProcessHeap(), 0, nSize);
151 /////////////////////////////////////////////////////////////////////////
152 // Enumerate file handles of the process.
155 DWORD dwFiles = 0;
157 // Get the handle of the target process. The handle will be used to
158 // duplicate the file handles in the process.
159 HANDLE hProcess = OpenProcess(
160 PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION, FALSE, pid);
161 if (hProcess == NULL)
163 _tprintf(_T("OpenProcess failed w/err 0x%08lx\n"), GetLastError());
164 return -1;
167 for (ULONG i = 0; i < pSysHandleInfo->NumberOfHandles; i++)
169 PSYSTEM_HANDLE pHandle = &(pSysHandleInfo->Handles[i]);
171 // Check for file handles of the specified process
172 if (pHandle->ProcessId == pid &&
173 pHandle->ObjectTypeNumber == HANDLE_TYPE_FILE)
175 dwFiles++; // Increase the number of file handles
177 // Duplicate the handle in the current process
178 HANDLE hCopy;
179 if (!DuplicateHandle(hProcess, (HANDLE)pHandle->Handle,
180 GetCurrentProcess(), &hCopy, MAXIMUM_ALLOWED, FALSE, 0))
181 continue;
183 // Retrieve file name information about the file object.
184 IO_STATUS_BLOCK ioStatus;
185 PFILE_NAME_INFORMATION pNameInfo = (PFILE_NAME_INFORMATION)
186 malloc(MAX_PATH * 2 * 2);
187 DWORD dwInfoSize = MAX_PATH * 2 * 2;
188 if (NtQueryInformationFile(hCopy, &ioStatus, pNameInfo,
189 dwInfoSize, FileNameInformation) == STATUS_SUCCESS)
191 // Get the file name and print it
192 WCHAR wszFileName[MAX_PATH + 1];
193 StringCchCopyNW(wszFileName, MAX_PATH + 1,
194 pNameInfo->FileName, /*must be WCHAR*/
195 pNameInfo->FileNameLength /*in bytes*/ / 2);
197 wprintf(L"0x%x:\t%s\n", pHandle->Handle, wszFileName);
199 free(pNameInfo);
201 CloseHandle(hCopy);
205 CloseHandle(hProcess);
208 /////////////////////////////////////////////////////////////////////////
209 // Clean up.
212 HeapFree(GetProcessHeap(), 0, pSysHandleInfo);
214 // Return the number of file handles in the process
215 return dwFiles;
218 #pragma endregion
221 #pragma region GetFileNameFromHandle
224 * Get file name from a handle to a file object using a file mapping object.
225 * It uses the CreateFileMapping and MapViewOfFile functions to create the
226 * mapping. Next, it uses the GetMappedFileName function to obtain the file
227 * name. For remote files, it prints the device path received from this
228 * function. For local files, it converts the path to use a drive letter and
229 * prints this path.
231 * \param hFile
232 * File handle
234 BOOL GetFileNameFromHandle(HANDLE hFile)
236 TCHAR szFileName[MAX_PATH + 1];
237 HANDLE hFileMap;
239 // Get the file size
240 DWORD dwFileSizeHi = 0;
241 DWORD dwFileSizeLo = GetFileSize(hFile, &dwFileSizeHi);
243 if (dwFileSizeLo == 0 && dwFileSizeHi == 0)
245 _tprintf(_T("Cannot map a file with a length of zero\n"));
246 return FALSE;
249 /////////////////////////////////////////////////////////////////////////
250 // Create a file mapping object.
253 // Create a file mapping to get the file name
255 hFileMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 1, NULL);
256 if (!hFileMap)
258 _tprintf(_T("CreateFileMapping failed w/err 0x%08lx\n"),
259 GetLastError());
260 return FALSE;
263 void* pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1);
264 if (!pMem)
266 _tprintf(_T("MapViewOfFile failed w/err 0x%08lx\n"), GetLastError());
267 CloseHandle(hFileMap);
268 return FALSE;
272 /////////////////////////////////////////////////////////////////////////
273 // Call the GetMappedFileName function to obtain the file name.
276 if (GetMappedFileName(GetCurrentProcess(), pMem, szFileName, MAX_PATH))
278 // szFileName contains device file name like:
279 // \Device\HarddiskVolume2\Users\JLG\AppData\Local\Temp\HLe6098.tmp
280 _tprintf(_T("Device name is %s\n"), szFileName);
282 // Translate path with device name to drive letters.
283 TCHAR szTemp[BUFFER_SIZE];
284 szTemp[0] = '\0';
286 // Get a series of null-terminated strings, one for each valid drive
287 // in the system, plus with an additional null character. Each string
288 // is a drive name. e.g. C:\\0D:\\0\0
289 if (GetLogicalDriveStrings(BUFFER_SIZE - 1, szTemp))
291 TCHAR szName[MAX_PATH];
292 TCHAR szDrive[3] = _T(" :");
293 BOOL bFound = FALSE;
294 TCHAR* p = szTemp;
298 // Copy the drive letter to the template string
299 *szDrive = *p;
301 // Look up each device name. For example, given szDrive is C:,
302 // the output szName may be \Device\HarddiskVolume2.
303 if (QueryDosDevice(szDrive, szName, MAX_PATH))
305 UINT uNameLen = _tcslen(szName);
307 if (uNameLen < MAX_PATH)
309 // Match the device name e.g. \Device\HarddiskVolume2
310 bFound = _tcsnicmp(szFileName, szName, uNameLen) == 0;
312 if (bFound)
314 // Reconstruct szFileName using szTempFile
315 // Replace device path with DOS path
316 TCHAR szTempFile[MAX_PATH];
317 StringCchPrintf(szTempFile, MAX_PATH, _T("%s%s"),
318 szDrive, szFileName + uNameLen);
319 StringCchCopyN(szFileName, MAX_PATH + 1,
320 szTempFile, _tcslen(szTempFile));
325 // Go to the next NULL character, i.e. the next drive name.
326 while (*p++);
328 } while (!bFound && *p); // End of string
333 /////////////////////////////////////////////////////////////////////////
334 // Clean up the file mapping object.
337 UnmapViewOfFile(pMem);
338 CloseHandle(hFileMap);
340 _tprintf(_T("File name is %s\n\n"), szFileName);
341 return TRUE;
344 #pragma endregion
347 int _tmain(int argc, _TCHAR* argv[])
349 // Enumerate file handles of a process using undocumented APIs
350 ULONG pid = GetCurrentProcessId();
351 DWORD dwFiles = EnumerateFileHandles(pid);
353 // Get file name from file handle using a file mapping object
354 /*HANDLE hFile = ...;
355 GetFileNameFromHandle(hFile);*/
357 return 0;